import json
from uuid import uuid4
from urllib.parse import urlencode, urlparse
from aiohttp import ClientSession, WSMsgType
import json

# from apps.base.hunter import AppError
from .auth import BaseXFYunHandler
    

class WSHandlerForChat(BaseXFYunHandler):
    '''星火认知大模型websocket请求操作类'''
    def __init__(self, 
                 app_id:str,
                 api_key:str,
                 api_secret:str,
                 api_url:str,
                 response_protocol:any = None,
                 session:ClientSession = None,
                ):
        super().__init__(app_id, api_key, api_secret, api_url, response_protocol, session)
        self.method = "GET"

    def gen_params(self, query: any, **kwargs) -> dict:
        '''生成请求数据'''
        def __get_domain(path:str) -> str:
            '''根据请求的path查出domain字段'''
            domain_list = {
                "/v4.0/chat": "4.0Ultra",
                "/v3.5/chat": "generalv3.5",
                "/chat/pro-128k": "pro-128k",
                "/v3.1/chat": "generalv3",
                "/v2.1/chat": "generalv2",
                "/v1.1/chat": "general",
            }
            return domain_list.get(path, "generalv3.5")
        uid = kwargs.get("user_id", uuid4().hex)
        max_tokens = kwargs.get("max_tokens", 500)
        question = [{"role": "user", "content": query},]
        # 历史问答信息
        with_context = kwargs.get("with_context",False)
        with_context and question.extend(self.get_conversation_context()) #这样写会被打死
        data = {
            "header": {
                "app_id": self.app_id,
                "uid": uid
            },
            "parameter": {
                "chat": {
                    "domain": __get_domain(self.path),
                    "temperature": 0.5,
                    "max_tokens": max_tokens
                }
            },
            "payload": {
                "message": {
                    "text": question
                }
            }
        }
        return  data
        
    @property
    def request_url(self) -> str:
        '''
        实际请求的url.
        子类中重写.
        一般uri中带鉴权的.返回self.__cerate_auth_url.不带的直接返回self.url
        详细看讯飞文档https://www.xfyun.cn/doc/,
        '''
        return self.create_auth_url()


class HTTPHandlerForChat(BaseXFYunHandler):
    '''星火认知大模型http请求操作类'''

    def __init__(self,
                 app_id:str,
                 api_key:str,
                 api_secret:str,
                 api_url:str,
                 response_protocol:any = None,
                 session:ClientSession = None,
                ):
        super().__init__(app_id, api_key, api_secret, api_url, response_protocol, session)
        self.__create_request_auth_headers()
        self.method = "POST"

    def gen_params(self, query: any, **kwargs) -> dict:
        model = kwargs.get("model", "generalv3.5")
        max_tokens = kwargs.get("max_tokens", 500)
        messages = [{"role": "user", "content": query},]
        with_context = kwargs.get("with_context",False)
        with_context and messages.extend(self.get_conversation_context()) #这样写会被打死
        data = {
            "model": model, # 指定请求的模型
            "max_tokens": max_tokens,
            "messages": messages,
   		    "stream": True
        }
        return data
    @property
    def request_url(self) -> str:
        return self.url

    def __create_request_auth_headers(self):
        authorization_headers = {"Authorization": F"Bearer {self.api_key}:{self.api_secret}"}
        self.headers.update(authorization_headers)


# class HTTPHandlerForChat(BaseXFYunAuth):
#     '''
#     星火认知大模型HTTP请求操作类
#     '''
#     def __init__(self, app_id:str, api_key:str, api_secret:str, api_url:str, response_Protocol, session:ClientSession = None, method:str="POST"):
#         self.app_id = app_id,
#         self.api_key = api_key
#         self.api_secret = api_secret
#         self.url = api_url
#         self.response_Protocol = response_Protocol
#         self.session = session
#         self.http = None
#         self.method = method
#         self.headers = self.__request_headers
        

#     async def async_connect(self):
#         if self.session is None:
#             self.session = ClientSession()

#     async def async_send_str(self, user_id:str, query:str):
#         be_send_data = self.gen_params(user_id, query)
#         print(be_send_data)
#         self.http = await self.session.post(self.url, json=be_send_data, headers = self.headers)

#     async def async_recv(self, callback:any = None):
#         while True:
#             chunk = await self.http.content.readany()
#             if (not chunk) or  b"data: [DONE]" in chunk:
#                 break
#             # data = json.loads(chunk.decode('utf-8')[6:])
#             data = chunk.decode("utf-8")
#             start_str = "data: "
#             start_str_len = len(start_str)
#             index = data.find(start_str)
#             data = data[index+start_str_len:]
#             if callback:
#                 await callback(data, self.response_Protocol)
#             # print(data)
#         # async for chunk in self.http.content.iter_chunked(1024):
#         #     if chunk is None or  b"data: [DONE]" in chunk:
#         #         break
#         #     print(chunk.decode('utf-8'))
#         self.http.close()
#         self.http = None
    
#     async def async_close_session(self):
#         if self.session is not None:
#             await self.session.close()
#             self.session = None

#     def gen_params(self, user_id: str = None, query: any= "") -> dict:
#         data = {
#             "model": "generalv3.5", # 指定请求的模型
#             "messages": [
#                 {
#                     "role": "user",
#                     "content": query
#                 }
#             ],
#    		    "stream": True
#         }
#         return data

#     @property
#     def __request_headers(self):
#         return {
#             "Authorization": F"Bearer {self.api_key}:{self.api_secret}" # 注意此处替换自己的key和secret
#         }


# class XFYunHandle(AstractXFYunAuthb):
#     '''讯飞星火大模型api操作类'''
#     headers = {"Content-Type": "application/json;charset=UTF-8"}
#     __wss_schemes = ("wss", "ws")
#     __https_schemes = ("https", "http")

#     def __init__(self, 
#                  app_id:str,
#                  api_key:str,
#                  api_secret:str,
#                  api_url:str,
#                  response_protocol:any = None,
#                  session:ClientSession = None,
#                  ):
#         self.app_id = app_id
#         self.api_key = api_key
#         self.api_secret = api_secret
#         self.url = api_url
#         self.scheme = urlparse(self.url).scheme
#         self.host = urlparse(self.url).netloc
#         self.path = urlparse(self.url).path
#         self.response_Protocol
#         self.session = session
#         self.request_Protocol = response_protocol
        
#     async def async_connect(self) -> None:
#         '''创建连接wss|https'''
#         if self.session is None:
#             self.session = ClientSession()
#         if self.scheme in ["wss","ws"]:
#             self.request_Protocol = await self.session.ws_connect(self.request_url)

#     async def async_send_str(self, query: str, user_id: UUID = None) -> None:
#         '''发送字符串数据'''
#         be_send_data = self.gen_params(user_id, query)
#         if self.scheme in self.__wss_schemes:
#             await self.request_Protocol.send_str(json.dumps(be_send_data))
#         elif self.scheme in self.__https_schemes:
#             self.request_Protocol = await self.session.post(self.request_url, json=be_send_data, headers = self.headers)
#         else:
#             pass

#     async def async_send_json(self, query: dict, user_id: UUID = None) -> None:
#         '''发送json数据'''
#         if self.scheme in self.__wss_schemes:
#             await self.request_Protocol.send_str(json.dumps(query))
#         elif self.scheme in self.__https_schemes:
#             self.request_Protocol = await self.session.post(self.request_url, json=query, headers = self.headers)
#         else:
#             pass

#     async def async_send_bytes(self, query: bytes, user_id: UUID = None) -> None:
#         # return await super().async_send_bytes(query, user_id)
#         pass

#     async def async_recv_data(self, callback: any = None) -> None:
#         '''
#         接收大模型api的响应数据

#         args:
#             callback : function|method  响应数据处理回调,要求有三个参数:
#                 args:
#                     reply : any 响应数据
#                     send_process : any 数据输出方法. 该参数是在实例化对象时传输给 self.response_Protocol 参数
#                             eg : send_process = print,  print(reply)输出到控制台. send_process = ws, ws.send_str(reply) 使用websocket发送
#                     obj : any 调用该回调的对象或者连接池, 以便在接收数据异常或接收完成后关闭连接. eg:
#                         callbakc(obj = self): 
#                                 await self.session.close()    
#         '''
#         if self.scheme in self.__wss_schemes:
#             await self.__async_handle_ws_data(callback)
#         elif self.scheme in self.__https_schemes:
#             await self.__async_handle_http_data(callback)

#     async def async_close_request_Protocol(self) -> None:
#         '''关闭连接'''
#         if hasattr(self.request_Protocol, 'close'):
#             await self.request_Protocol.close()
#             self.request_Protocol = None

#     async def async_close_session(self) -> None:
#         # return await super().async_close_session()
#         '''关闭session'''
#         if hasattr(self.session, "close"):
#             await self.session.close()
#             self.session = None

#     async def __async_handle_ws_data(self, callback:any = None):
#         '''
#          接收websocket返回的数据,使用回调函数处理数据。
#          只专注接收，响应给客户端交由回调来做
#         '''
#         async for msg in self.request_Protocol:
#             if msg.type == WSMsgType.CLOSED:
#                 break
#             if callback:
#                 await callback(msg, self.response_Protocol, self)
#         await self.async_close_request_Protocol()


#     async def __async_handle_http_data(self, callback:any = None):
#         '''
#          接收http返回的数据,使用回调函数处理数据。
#          只专注接收，响应给客户端交由回调来做
#         '''
#         while True:
#             chunk = await self.request_Protocol.content.readany()
#             if (chunk is None) or (b'data: [DONE]' in chunk):
#                 break
#             data = chunk.decode("utf-8")
#             start_str = "data: "
#             start_str_len = len(start_str)
#             index = data.find(start_str)
#             data = data[index+start_str_len:] #xfyunapi 去掉开头的data字段
#             if callback:
#                 await callback(data, self.response_Protocol, self)
#             await self.async_close_request_Protocol()

